<?php
/*
 * Logging Class
 * Written by Howard Liu <howard@ixnet.work>
 * Licensed under MIT
 */

namespace IXNetwork\Lib\Tool;

class Logging
{
    private $logFile;
    private $token = false;
    public $ip = false;
    private $timeFormat = 'Y/m/d H:i:s e'; //Format of date()

    /**
     * ixLogging constructor.
     *
     * @param string     $logFile
     * @param string     $timeFormat
     * @param bool|array $token
     * @param bool       $isIP
     * @param bool       $isIPLengthFixed
     */
    public function __construct(
        $logFile = './general.log',
        $timeFormat = null,
        $token = [false],
        $isIP = false,
        $isIPLengthFixed = true
    ) {
        //Generate log file folders
        if ($pos = strrpos($logFile, '/')) {
            if (!file_exists($folder = substr($logFile, 0, $pos))) {
                mkdir($folder, 0777, true);
            }
        } elseif ($pos = strrpos($logFile, '\\')) {
            if (!file_exists($folder = substr($logFile, 0, $pos))) {
                mkdir(substr($folder, 0777, true));
            }
        }
        $this->logFile = fopen($logFile, 'at');

        /**
         * Array token
         * $token[1] bool, means weather token is enabled
         * $token[2] int,  means the length of random codes for md5 sum
         * $token[3] int,  means the length of the token
         */
        if ($token[0]) {
            $this->generateNewToken($token);
        }
        if ($isIP) {
            $this->ip = $this->getIP($isIPLengthFixed);
        }
        if ($timeFormat) {
            $this->timeFormat = $timeFormat;
        }
        $this->add(' [INFO] Logging Class Initiated');
    }

    /**
     * Print a message
     *
     * @param  $message
     * @return bool|string string if succeed and bool(false) if failed
     */
    public function add($message)
    {
        $write = '['.date($this->timeFormat).']';
        if ($this->ip) {
            $write .= '['.$this->ip.']';
        }
        if ($this->token) {
            $write.= '['.$this->token.']';
        }
        return fwrite($this->logFile, $write.$message."\n") ? $write.$message : false;
    }

    /**
     * Get Remote User's IP
     *
     * @param  $isIPLengthFixed
     * @return bool|string
     */
    private function getIP($isIPLengthFixed)
    {
        if (getenv("HTTP_X_FORWARDED_FOR")) {
            $ip = getenv("HTTP_X_FORWARDED_FOR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $ip = getenv("HTTP_CLIENT_IP");
        } elseif (getenv("REMOTE_ADDR")) {
            $ip = getenv("REMOTE_ADDR");
        } else {
            $ip = "Unknown";
        }

        // Fix the length of IP for a nicer log
        // E.g. 100.3.14.45 --> 100.003.014.045
        if ($isIPLengthFixed) {
            if ($ip == "Unknown") {
                $ip = "****Unknown****";
            } else {
                $ip = explode(',', $ip);
                $newIP = explode('.', $ip[0]);
                $ip = '';
                foreach ($newIP as $i) {
                    $ip .= sprintf("%03d", $i).".";
                }
            }
            $ip = substr($ip, 0, 15);
        }
        return $ip;
    }

    /**
     * Write a message to the log file that the session has been terminated.
     * @return int
     */
    public function terminate()
    {
        $this->add(' [INFO] Session Terminated');
        $this->generateNewToken();
        return true;
    }

    private function generateNewToken($token = [])
    {
        if (isset($token[1]) && is_int($token[1])) {
            if (isset($token[2])&& is_int($token[2])) {
                return $this->token = Str::random($token[1], $token[2]);
            } else {
                return $this->token = Str::random($token[1]);
            }
        } else {
            return $this->token = Str::random();
        }
    }
}
